package com.ruoyi.encrypt.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import com.ruoyi.core.exception.RunException;
import com.ruoyi.core.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author wanghao 913351190@qq.com
 * @create 2022/6/20 16:09
 */
@Slf4j
public class SM2Util {


    public static String generateKey() {
        KeyPair pair = SecureUtil.generateKeyPair("SM2");
        byte[] privateKey = pair.getPrivate().getEncoded();
        byte[] publicKey = pair.getPublic().getEncoded();
        String privateKey1 = Base64.encode(privateKey);
        String publicKey1 = Base64.encode(publicKey);
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("privateKey", privateKey1);
        result.put("publicKey", publicKey1);
        return JsonUtil.toJson(result);
    }


    private static final String PRIVATE_KEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg6gfXZvsZxYysKMAubYQGaBkMZ1DKIaMA+veMw8BbR3mgCgYIKoEcz1UBgi2hRANCAARjjfEDbiXhVkivK1L0P29itg631mN90QuoTJtSTuVD9dF3aViOVNgsuSSViHwzJlxsQ5TFNMq7HWA3tDPuRMeS";
    private static final String PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEY43xA24l4VZIrytS9D9vYrYOt9ZjfdELqEybUk7lQ/XRd2lYjlTYLLkklYh8MyZcbEOUxTTKux1gN7Qz7kTHkg==";

    public static String encrypt(String text) {
        // 公钥加密
        SM2 sm2 = SmUtil.sm2(PRIVATE_KEY, PUBLIC_KEY);
        byte[] encrypt = sm2.encrypt(text, KeyType.PublicKey);
        return Base64.encode(encrypt);
    }

    public static String decrypt(String text) {
        // 私钥解密
        SM2 sm2 = SmUtil.sm2(PRIVATE_KEY, PUBLIC_KEY);
        byte[] decode = Base64.decode(text);
        return StrUtil.utf8Str(sm2.decrypt(decode, KeyType.PrivateKey));
    }

    /**
     * 私钥签名
     *
     * @param privateKey 私钥
     * @param content    报文原文
     * @return
     */
    public static String sign(String privateKey, String content) {
        if (StringUtils.isEmpty(privateKey)) {
            throw new RunException("签名密钥为空");
        }
        if (StringUtils.isEmpty(content)) {
            throw new RunException("签名报文为空");
        }
        try {
            SM2 sm2 = SmUtil.sm2(privateKey, null);
            return Base64.encode(sm2.sign(content.getBytes(StandardCharsets.UTF_8)));
        } catch (Exception e) {
            log.error("签名失败", e);
            throw new RunException("签名失败");
        }
    }

    /**
     * 私钥签名
     *
     * @param privateKey 私钥
     * @param content    报文原文
     * @return
     */
    public static String sign(String privateKey, byte[] content) {
        if (StringUtils.isEmpty(privateKey)) {
            throw new RunException("签名密钥为空");
        }
        if (Objects.isNull(content) || content.length == 0) {
            throw new RunException("签名报文为空");
        }
        try {
            SM2 sm2 = SmUtil.sm2(privateKey, null);
            return Base64.encode(sm2.sign(content));
        } catch (Exception e) {
            log.error("签名失败", e);
            throw new RunException("签名失败");
        }
    }

    /**
     * 公钥验签
     *
     * @param publicKey 公钥
     * @param content   报文原文
     * @param sign      签名字符串
     * @return
     */
    public static boolean verifySign(String publicKey, String content, String sign) {
        if (StringUtils.isEmpty(publicKey)) {
            throw new RunException("验签密钥为空");
        }
        if (StringUtils.isEmpty(content)) {
            throw new RunException("验签报文为空");
        }
        if (StringUtils.isEmpty(sign)) {
            throw new RunException("验签签名为空");
        }
        try {
            SM2 sm2 = SmUtil.sm2(null, publicKey);
            return sm2.verify(content.getBytes(StandardCharsets.UTF_8), Base64.decode(sign));
        } catch (Exception e) {
            log.error("验签失败", e);
            throw new RunException("验签失败");
        }
    }

    /**
     * 公钥验签
     *
     * @param publicKey 公钥
     * @param content   报文原文
     * @param sign      签名字符串
     * @return
     */
    public static boolean verifySign(String publicKey, byte[] content, String sign) {
        if (StringUtils.isBlank(publicKey)) {
            log.error("SM2公钥为空!sm2签名校验失败!");
            throw new RuntimeException("SM2公钥为空!SM2签名校验失败!");
        }
        if (StringUtils.isBlank(sign)) {
            log.error("签名为空!签名校验失败!");
            throw new RuntimeException("签名为空!SM2签名校验失败!");
        }
        if (Objects.isNull(content) || content.length == 0) {
            log.error("报文为空!SM2签名校验失败!");
            throw new RuntimeException("报文为空!SM2签名校验失败!");
        }
        try {
            SM2 sm2 = SmUtil.sm2(null, publicKey);
            return sm2.verify(content, Base64.decode(sign));
        } catch (Exception e) {
            log.error("SM2签名校验失败!", e);
            throw new RuntimeException("SM2签名校验失败" + e.getMessage());
        }
    }

}
